#include <jni.h>
#include <android/log.h>
#include <malloc.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

#define TAG "hid-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

static const unsigned char HidDescriptorTable[] = {
        0x05, 0x01,  // USAGE_PAGE (Generic Desktop)
        0x09, 0x02,  // USAGE (Mouse)
        0xa1, 0x01,  // COLLECTION (Application)
        0x09, 0x01,  //   USAGE (Pointer)
        0xa1, 0x00,  //   COLLECTION (Physical)
        0x85, 0x02,  //     REPORT_ID (2)
        0x05, 0x09,  //     USAGE_PAGE (Button)
        0x19, 0x01,  //     USAGE_MINIMUM (Button 1)
        0x29, 0x03,  //     USAGE_MAXIMUM (Button 3)
        0x15, 0x00,  //     LOGICAL_MINIMUM (0)
        0x25, 0x01,  //     LOGICAL_MAXIMUM (1)
        0x95, 0x03,  //     REPORT_COUNT (3)
        0x75, 0x01,  //     REPORT_SIZE (1)
        0x81, 0x02,  //     INPUT (Data,Var,Abs)
        0x95, 0x01,  //     REPORT_COUNT (1)
        0x75, 0x05,  //     REPORT_SIZE (5)
        0x81, 0x03,  //     INPUT (Cnst,Var,Abs)
        0x05, 0x01,  //     USAGE_PAGE (Generic Desktop)
        0x09, 0x30,  //     USAGE (X)
        0x09, 0x31,  //     USAGE (Y)
        0x15, 0x81,  //     LOGICAL_MINIMUM (-127)
        0x25, 0x7f,  //     LOGICAL_MAXIMUM (127)
        0x75, 0x08,  //     REPORT_SIZE (8)
        0x95, 0x02,  //     REPORT_COUNT (2)
        0x81, 0x06,  //     INPUT (Data,Var,Rel)
        0x09, 0x38,  //     USAGE (Wheel)
        0x15, 0x81,  //     LOGICAL_MINIMUM (-127)
        0x25, 0x7f,  //     LOGICAL_MAXIMUM (127)
        0x75, 0x08,  //     REPORT_SIZE (8)
        0x95, 0x01,  //     REPORT_COUNT (1)
        0x81, 0x06,  //     INPUT (Data,Var,Rel)
        0xc0, // END_COLLECTION
        0xc0,  // END_COLLECTION

        // battery strength
        0x05, 0x0c,
        0x09, 0x01,
        0xa1, 0x01,
        0x85, 0x20,  //   REPORT_ID (32)
        0x05, 0x01,
        0x09, 0x06,
        0xa1, 0x02,
        0x05, 0x06,  // USAGE_PAGE (Generic Device Controls)
        0x09, 0x20,  // USAGE (Battery Strength)
        0x15, 0x00,  // LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,  // LOGICAL_MAXIMUM (100)
        0x75, 0x08,  // REPORT_SIZE (8)
        0x95, 0x01,  // REPORT_COUNT (1)
        0x81, 0x02,  // INPUT (Data,Var,Abs)
        0xc0, // END_COLLECTION
        0xc0, // END_COLLECTION

        0x05, 0x01,  // USAGE_PAGE (Generic Desktop)
        0x09, 0x06,  // USAGE (Keyboard)
        0xa1, 0x01,  // COLLECTION (Application)
        0x85, 0x01,  //   REPORT_ID (1)
        0x05, 0x07,  //   USAGE_PAGE (Keyboard)
        0x19, 0xe0,  //   USAGE_MINIMUM (Keyboard LeftControl)
        0x29, 0xe7,  //   USAGE_MAXIMUM (Keyboard Right GUI)
        0x15, 0x00,  //   LOGICAL_MINIMUM (0)
        0x25, 0x01,  //   LOGICAL_MAXIMUM (1)
        0x75, 0x01,  //   REPORT_SIZE (1)
        0x95, 0x08,  //   REPORT_COUNT (8)
        0x81, 0x02,  //   INPUT (Data,Var,Abs)
        0x05, 0x0c,  //   USAGE_PAGE (Consumer Devices)
        0x15, 0x00,  //   LOGICAL_MINIMUM (0)
        0x25, 0x01,  //   LOGICAL_MAXIMUM (1)
        0x95, 0x07,  //   REPORT_COUNT (7)
        0x75, 0x01,  //   REPORT_SIZE (1)
        0x09, 0xb6,  //   USAGE (Scan Previous Track)
        0x09, 0xb5,  //   USAGE (Scan Next Track)
        0x09, 0xb7,  //   USAGE (Stop)
        0x09, 0xcd,  //   USAGE (Play/Pause)
        0x09, 0xe2,  //   USAGE (Mute)
        0x09, 0xe9,  //   USAGE (Volume Up)
        0x09, 0xea,  //   USAGE (Volume Down)
        0x81, 0x02,  //   INPUT (Data,Var,Abs)
        0x95, 0x01,  //   REPORT_COUNT (1)
        0x75, 0x01,  //   REPORT_SIZE (1)
        0x81, 0x03,  //   INPUT (Constant,Var,Abs)
        0x05, 0x07,  //   USAGE_PAGE (Keyboard)
        0x95, 0x05,  //   REPORT_COUNT (5)
        0x75, 0x01,  //   REPORT_SIZE (1)
        0x85, 0x01,  //   REPORT_ID (1)
        0x05, 0x08,  //   USAGE_PAGE (LEDs)
        0x19, 0x01,  //   USAGE_MINIMUM (Num Lock)
        0x29, 0x05,  //   USAGE_MAXIMUM (Kana)
        0x91, 0x02,  //   OUTPUT (Data,Var,Abs)
        0x95, 0x01,  //   REPORT_COUNT (1)
        0x75, 0x03,  //   REPORT_SIZE (3)
        0x91, 0x03,  //   OUTPUT (Cnst,Var,Abs)
        0x95, 0x06,  //   REPORT_COUNT (6)
        0x75, 0x08,  //   REPORT_SIZE (8)
        0x15, 0x00,  //   LOGICAL_MINIMUM (0)
        0x25, 0x65,  //   LOGICAL_MAXIMUM (101)
        0x05, 0x07,  //   USAGE_PAGE (Keyboard)
        0x19, 0x00,  //   USAGE_MINIMUM (Reserved (no event indicated))
        0x29, 0x65,  //   USAGE_MAXIMUM (Keyboard Application)
        0x81, 0x00,  //   INPUT (Data,Ary,Abs)
        0xc0, // END_COLLECTION

        0x05, 0x01, //USAGE_PAGE (Generic Desktop)
        0x09, 0x05, //USAGE (Game Pad)
        0xA1, 0x01, //    COLLECTION (Application)
        0x85, 0x03, //    REPORT_ID (3)
        0x09, 0x01, //    USAGE (Pointer)
        0xA1, 0x00, //        COLLECTION (Physical)
        0x09, 0x30, //        USAGE (X)
        0x09, 0x31, //        USAGE (Y)
        0x15, 0x81, //        LOGICAL_MINIMUM (-127)
        0x25, 0x7F, //        LOGICAL_MAXIMUM (127)
        0x75, 0x08, //        REPORT_SIZE (8)
        0x95, 0x02, //        REPORT_COUNT (2)
        0x81, 0x02, //        INPUT (Data,Var,Abs)
        0xC0, //               END_COLLECTION
        0x05, 0x09, //    USAGE_PAGE (Button)
        0x19, 0x01, //    USAGE_MINIMUM (Button 1)
        0x29, 0x08, //    USAGE_MAXIMUM (Button 8)
        0x15, 0x00, //    LOGICAL_MINIMUM (0)
        0x25, 0x01, //    LOGICAL_MAXIMUM (1)
        0x95, 0x08, //    REPORT_COUNT (8)
        0x75, 0x01, //    REPORT_SIZE (1)
        0x81, 0x02, //    INPUT (Data,Var,Abs)
        0xC0, //          END_COLLECTION
};

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    //LOGI("JNI_OnLoad");
    return JNI_VERSION_1_6;
}

JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
    //LOGI("JNI_OnUnload");
}

JNIEXPORT jbyteArray JNICALL Java_com_benjaminwan_read_free_lib_HidDefinition_getHidDescriptor
        (JNIEnv *env, jobject thiz) {
    int size = sizeof(HidDescriptorTable);
    jbyteArray result = (*env).NewByteArray(size);
    (*env).SetByteArrayRegion(result, 0, size, reinterpret_cast<const jbyte *>(HidDescriptorTable));
    return result;
}

#ifdef __cplusplus
}
#endif